

import UIKit


enum KGRefreshViewState {
    case State_Idle
    
    // 处于正在刷新状态
    case DidRefresh
    
    // 处于用户拖动拉拽跟踪状态，但仍然未达到临界点
    case Ready
    
    // 已经到达可以启动刷新的临界点，如果用户这时候释放触摸，那么就开始刷新
    // 想象一下，当用户的手指触摸滚动视图向下拉时，有一个临界点，当用户拖动的距离没有到达临界点或者从临界点后又回到临界点之前
    // 释放触摸，那么我们认为用户不希望刷新，那么我们就什么都不用做，如果用户在临界点之后释放，那么我们就认为用户希望启动刷新
    case WillRefresh
}

enum KGRefreshViewMode {
    
    case None
    case Push
    case Pull
    
}


class KGRefreshView: UIView {
    
    
    var refreshing: Bool {
        
        get {
            return (state == .DidRefresh)
        }
        
    }
    
    
    
    var titleForPullRefresh = "下拉刷新"
    var titleForReadyPullRefresh = "释放刷新"
    var titleForPullRefreshing = "刷新中..."
    

    
    
    
    private var isObserved = false
    
    private var textLabel = UILabel()
    private var iconView = UIArrowView()
    private var progressView = UICircleView()
    
    
    private var _scrollView: UIScrollView?
    

    
    private var _target: AnyObject?
    private var _selector: Selector?
    
    
    func AddTarget(target: AnyObject, selector: Selector) {
        
        _target = target
        _selector = selector
        
    }
    
    
    override func willMoveToSuperview(newSuperview: UIView?) {
        
        if (newSuperview == nil) {
            
            removeObservers()
            
            _scrollView = nil
        }
        else {
            
            if textLabel.superview !== self {
                addSubview(textLabel)
                textLabel.textColor = self.tintColor
            }
            
            if iconView.superview !== self {
                addSubview(iconView)
                iconView.backgroundColor = UIColor.clearColor()
                
            }
            
            if progressView.superview !== self {
                addSubview(progressView)
                progressView.backgroundColor = UIColor.clearColor()
                //progressView.progress = 0.95
            }
            
            _scrollView = newSuperview as? UIScrollView
            
            addObservers()
        }
        
        
    }
    
    
    
    override func layoutSubviews() {
        
        
        let sizeForImage = CGSize(width: 30, height: 30)
        
        let spacing = CGFloat(8.0)
        
        var textRect = CGRect(x: 0, y: 0, width: 0, height: 0)
        
        
        if (textLabel.text != nil) {
            
            textRect = textLabel.textRectForBounds(CGRect(origin: CGPoint.zero, size: CGSize(width: self.bounds.width - sizeForImage.width - spacing, height: self.bounds.height)), limitedToNumberOfLines: 1)
            
        }
        
        
        var offsetX = (self.bounds.width - (sizeForImage.width + textRect.width + spacing)) / 2
        
        iconView.frame = CGRect(x: offsetX, y: (self.bounds.height - sizeForImage.height) / 2 , width: sizeForImage.width, height: sizeForImage.height)
        progressView.frame = iconView.frame
        
        offsetX += sizeForImage.width + spacing
        
        textLabel.frame = CGRect(x: offsetX, y: (self.bounds.height - textRect.height) / 2 , width: textRect.width, height: textRect.height)
        
        
        
        
    }
    
    func StartAnimation()
    {
        
        //let animation =  CABasicAnimation(keyPath: "opacity")
        let animation = CABasicAnimation(keyPath: "transform.rotation.z")
        
        animation.duration = NSTimeInterval(1.0)
        animation.toValue = 2.0 * M_PI
        animation.fromValue = 0.0
        animation.removedOnCompletion = true
        animation.repeatCount = 9999999
        
        progressView.layer.addAnimation(animation, forKey: "dfadfa")
        
    }
    
    
    private func addObservers() {
        
        if (_scrollView != nil && !isObserved) {
            
            isObserved = true
            
            _scrollView!.addObserver(self, forKeyPath: "contentOffset", options: NSKeyValueObservingOptions.New, context: nil)
            _scrollView!.addObserver(self, forKeyPath: "bounds", options: NSKeyValueObservingOptions.New, context: nil)
            _scrollView!.addObserver(self, forKeyPath: "contentInset", options: NSKeyValueObservingOptions.New, context: nil)
        }
    }
    
    private func removeObservers() {
        
        if isObserved {
            
            isObserved = false
            
            _scrollView!.removeObserver(self, forKeyPath: "contentOffset")
            _scrollView!.removeObserver(self, forKeyPath: "bounds")
            _scrollView!.removeObserver(self, forKeyPath: "contentInset")
        }
        
    }
    
    private var bReadyToRefresh = false
    
    
    private var state = KGRefreshViewState.State_Idle
    var mode = KGRefreshViewMode.None
    
    // 计算滚动的范围
    func scrollRange() -> CGFloat {
        
        // 先获得滚动窗口的大小，就是滚动视图的窗口高度扣除上下的 Inset    
        let scrollWindowHeight = _scrollView!.frame.height - _scrollView!.contentInset.top - _scrollView!.contentInset.bottom
        
        // 然后用滚动内容的高度减去滚动窗口的高度
        let scrollRangeY = _scrollView!.contentSize.height - scrollWindowHeight
        
        //修正一下后返回，如果小过零，说明滚动的内容小于滚动窗口，所以不需要滚动就能看到全部
        
        return max(0.0, scrollRangeY)
        
    }
    
    
    func beginRefresh() {
        
        state = .DidRefresh
        
        
        if mode == .Pull {
            textLabel.text = titleForPullRefreshing
            layoutSubviews()
            _scrollView!.contentInset.top = _scrollView!.contentInset.top + 60.0
            _scrollView?.scrollEnabled = false
            
            StartAnimation()
            
        }
        
        _target?.performSelector(_selector!, withObject: self)

    }
    
    func endRefresh(){
        
        state = .State_Idle
        
        if mode == .Pull {
            progressView.layer.removeAllAnimations()
            
            
            _scrollView!.contentInset.top = _scrollView!.contentInset.top - 60.0
            
            UIView.animateWithDuration(10, animations: {
                
            })
            
            
            
            _scrollView?.scrollEnabled = true
            
            
        }
        
        
    }
    
    
    // 上推获取更多数据时候，提前量，例如我们希望当用户推到里最后的位置还差一定距离时候，开始触发上推事件，提前读取更多数据
    private let forcast : CGFloat = 50.0
    
    // 临界值，当下拉到临界值的时候释放会触发刷新
    private let threshold : CGFloat = -60.0
    

    private var delta: CGFloat = 0.0
    
    
    var NoMoreData = false
    
    override func observeValueForKeyPath(keyPath: String?, ofObject object: AnyObject?, change: [String : AnyObject]?, context: UnsafeMutablePointer<Void>) {
        
        
        
        
        switch keyPath! {
            
        case "contentOffset":
            
            
            if state == .DidRefresh {
                
                
            }
            else {
                
                // 不能单纯的通过判断 UIScrollView 的 Dragging 来判断用户是否在拖动滚动视图，因为我发现当我们快速推动或者拉动
                // 滚动视图，即使手指已经离开屏幕，但是在滚动视图在惯性滚动一段距离的时间段内，Dragging标识仍然为真，如果我们希望
                // 严格区分是惯性作用滚动还是用户手指拖动滚动时，加上对 UIScrollView 的tracking 标识的判断
                

                
                
                
                
                if _scrollView!.dragging {
                    
                    

                    
                    let delta = _scrollView!.contentOffset.y + _scrollView!.contentInset.top
                    
                    
                    
                    if delta < 0.0 {
                        
                        // 下拉
                        
                        hidden = false
                        // 我们总是希望用户用手指拖动的方式来确定是否希望刷新
                        if _scrollView!.tracking {
                            if delta < threshold {
                                
                                state = .WillRefresh
                                mode = .Pull
                                textLabel.text = titleForReadyPullRefresh
                                layoutSubviews()
                                
                                
                            }
                            else {
                                
                                state = .Ready
                                textLabel.text = titleForPullRefresh
                                layoutSubviews()

                            }
                        }
                        
                        let percentage = delta / threshold
                        
                        progressView.progress = min(0.95, percentage)
                        
                        
                        
                    }
                        
                    // 在上推的过程中，我们并没有那么严格的需要知道用户是否还在拖拽过程中
                    else if delta >= max(0.0, (scrollRange() - forcast)) {
                        

                        
                        if !NoMoreData {
                            
                            mode = .Push
                            beginRefresh()
                        
                            
                            
                        }
                        

                        
                    }
                    else {
                        
                        //mode = .None
                    }
                    
                    
                    
                    
                }
                else {
                    
                    if state == .WillRefresh {
                        
                        beginRefresh()
                        
                    }
                    else {
                        hidden = true
                    }
                    
                    
                }
                
            }
            
            
            break
            
        case "bounds":
            
            self.frame = CGRect(x: 0, y: -60, width: (superview?.bounds.width)!, height: 60)
            
            
        case "contentInset":
            
            break
            
            
        default: break
        }
        
    }
    
}


class UIArrowView: UIView {
    
    
    override func drawRect(rect: CGRect) {
        
        
        
        tintColor.setStroke()
        
        
        let centerPoint = CGPointMake(rect.midX, rect.midY)
        let arrowBezier = UIBezierPath()
        arrowBezier.lineWidth = 2.0
        arrowBezier.moveToPoint(CGPoint(x: centerPoint.x, y: centerPoint.y - 6))
        arrowBezier.addLineToPoint(CGPoint(x: centerPoint.x, y: centerPoint.y + 7))
        
        arrowBezier.moveToPoint(CGPoint(x: centerPoint.x, y: centerPoint.y + 6))
        arrowBezier.addLineToPoint(CGPoint(x: centerPoint.x - 6, y: centerPoint.y))
        
        arrowBezier.moveToPoint(CGPoint(x: centerPoint.x, y: centerPoint.y + 6))
        arrowBezier.addLineToPoint(CGPoint(x: centerPoint.x + 6, y: centerPoint.y))
        
        arrowBezier.stroke()
        
    }
    
    
}

class UICircleView: UIView {
    
    private var _progress = CGFloat(0.0)
    
    
    var progress: CGFloat {
        
        set {
            _progress = newValue
            setNeedsDisplay()
        }
        
        get {
            return _progress
        }
        
    }
    
    var radius = 14
    
    override func drawRect(rect: CGRect) {
        // Drawing code
        
        let myBezier = UIBezierPath()
        
        tintColor.setStroke()
        
        let centerPoint = CGPointMake(rect.midX, rect.midY)
        
        myBezier.addArcWithCenter(centerPoint, radius: CGFloat(radius), startAngle: CGFloat(1.5 * M_PI), endAngle: CGFloat((1.5 + Double(progress) * 2.0) * M_PI), clockwise: true)
        myBezier.stroke()
        
    }
}


